<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
      // 要监听 library 的属性 book1,book2 ;还要监听book1对象的name属性
      var library = {
        book1:{
          name:''
        },
        book2:''
      }
      function observe (data) { // 传进来的对象有条件
        if(!data || typeof(data) !== 'object'){
          return
        }
        var keyArr = Object.keys(data)
        // 如果 keyArr 的元素是一个对象，遍历这个数组
        keyArr.forEach(key => {
            console.log(key)
            defineReactive(data,key,data[key]) // 原来的对象、book1、
        })
      }
      function defineReactive (data,key,val) {
        // 如果val是一个变量，继续监听,如果不是，就跳出
        observe(val)
        // 劫持对象的属性
        // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
        Object.defineProperty(data,key,{
          configurable: true, // 当且仅当该属性的 configurable 键值为 true 时，该属性的描述符才能够被改变，同时该属性也能从对应的对象上被删除。
          enumerable: true, // 当且仅当该属性的 enumerable 键值为 true 时，该属性才会出现在对象的枚举属性中。
          set (newVal) {
            val = newVal
            console.log(`属性${key}已经被监听了，监听后的值为${newVal}`)
          },
          get () {
            // 如果监听到了，就通知订阅者
            return val
          }
        })
      }
      observe(library)
      library.book1.name="第一本书"
      library.book2="第二本书"


      // Object.keys(data) 得到的是一个数组 
      console.log(Object.keys(library)) //  ["book1", "book2"]
    </script>
</body>
</html>